package com.zxy.ziems.server.utils;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.zxy.btp.common.exception.ConditionException;
import com.zxy.ziems.server.constant.DateType;
import com.zxy.ziems.server.dto.DateDto;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * @ClassName 日期转换工具类
 * @Description
 * @Author 邓伟
 * @Date 2023/12/1 10:57
 * @Version 1.0
 */
public class DateUtils {

    public static final String PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String YMD_PATTERN = "yyyy-MM-dd";
    public static final String YM_PATTERN = "yyyy-MM";
    public static final String MD_PATTERN = "MM-dd";
    public static final String YYM_PATTERN = "yy-MM";
    public static final String YYM_PONT_PATTERN = "yy.MM";
    public static final String D_PATTERN = "dd";
    public static final String YMD_H_PATTERN = "yyyy-MM-dd HH";
    public static final String YEAR_PATTERN = "yyyy";
    public static final String YEAR_WEEK_PATTERN = "yyyy-ww";

    private static final DateTimeFormatter FORMATE = DateTimeFormatter.ofPattern(PATTERN);
    private static final DateTimeFormatter DATEFORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * 根据查询类型，计算统计图的x轴
     *
     * @param queryType
     * @param startDateStr 每个类型下的第一天的日期
     * @param endDateStr
     * @return
     */
    public static List<LocalDateTime> dateToList(String queryType, String startDateStr, String endDateStr) {
        List<LocalDateTime> list = new ArrayList<>();
        switch (queryType) {
            case DateType.DAY -> dayToHour(startDateStr, list);
            case DateType.DAY_HALF_HOUR -> dayToHalfHour(startDateStr, list);
            case DateType.SEVEN_DAY -> monthToDay(startDateStr, endDateStr, list);
            case DateType.WEEK -> weekToDay(startDateStr, list);
            case DateType.MONTH -> monthToDay(startDateStr, endDateStr, list);
            case DateType.YEAR -> yearToMonth(startDateStr, endDateStr, list);
            case DateType.CUSTOM -> monthToDay(startDateStr, endDateStr, list);
            case DateType.HIS_YEAR -> hisYearToYear(startDateStr, endDateStr, list);
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return list;
    }


    /**
     * 根据查询类型，计算统计图的x轴
     *
     * @param queryType
     * @param startDateStr 每个类型下的第一天的日期
     * @param endDateStr
     * @param isAll        是否全部，false，则不会超过当前时间则不会；true，会按正月整天这种返回
     * @return
     */
    public static List<LocalDateTime> dateToList(String queryType, String startDateStr, String endDateStr, boolean isAll) {
        List<LocalDateTime> list = new ArrayList<>();
        switch (queryType) {
            case DateType.DAY -> dayToHour(startDateStr, list, isAll);
            case DateType.WEEK -> weekToDay(startDateStr, list);
            case DateType.MONTH -> monthToDay(startDateStr, endDateStr, list);
            case DateType.YEAR -> yearToMonth(startDateStr, endDateStr, list, isAll);
            case DateType.CUSTOM -> monthToDay(startDateStr, endDateStr, list);
            case DateType.HIS_YEAR -> hisYearToYear(startDateStr, endDateStr, list);
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return list;
    }

    /**
     * 根据查询类型，计算统计图的x轴
     *
     * @param queryType
     * @param startDateStr 每个类型下的第一天的日期
     * @param endDateStr
     * @return
     */
    public static List<LocalDateTime> dateToList1(String queryType, String startDateStr, String endDateStr) {
        List<LocalDateTime> list = new ArrayList<>();
        switch (queryType) {
            case DateType.DAY -> dayToHour(startDateStr, list);
            case DateType.WEEK -> weekToDay(startDateStr, list);
            case DateType.MONTH -> monthToDay(startDateStr, endDateStr, list);
            case DateType.YEAR -> yearToMonth(startDateStr, endDateStr, list);
            case DateType.CUSTOM -> monthToDay(startDateStr, endDateStr, list);
            case DateType.HIS_YEAR -> hisYearToYear(startDateStr, endDateStr, list);
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return list;
    }

    private static void hisYearToYear(String startDateStr, String endDateStr, List<LocalDateTime> list) {

        LocalDateTime startDate = LocalDateTime.parse(startDateStr + " 00:00:00", FORMATE);
        LocalDateTime endDate = LocalDateTime.parse(endDateStr + " 00:00:00", FORMATE);
        //计算两个日期的间隔天数
        for (int year = startDate.getYear(); year <= endDate.getYear(); year++) {
            startDateStr = year + "-01-01 00:00:00";
            list.add(LocalDateTime.parse(startDateStr, FORMATE));
        }
    }

    /**
     * 按照查询类型，将时间转换为对应的字符串格式
     *
     * @param queryType
     * @param localDateTime
     * @return
     */
    public static String getDateStrByQueryType(String queryType, LocalDateTime localDateTime) {
        if (queryType.equals(DateType.DAY) || queryType.equals(DateType.DAY_HALF_HOUR)) {
            LocalTime localTime = localDateTime.toLocalTime();
            return localTime.format(DateTimeFormatter.ofPattern("HH:mm"));
        } else if (queryType.equals(DateType.YEAR)) {
            LocalDate localDate = localDateTime.toLocalDate();
            return localDate.format(DateTimeFormatter.ofPattern("yyyy-MM"));
        } else if (queryType.equals(DateType.HIS_YEAR)) {
            LocalDate localDate = localDateTime.toLocalDate();
            return localDate.format(DateTimeFormatter.ofPattern("yyyy"));
        } else {
            LocalDate localDate = localDateTime.toLocalDate();
            return localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }
    }

    /**
     * 将本周期和上一个周期的时间按步长进行对应
     *
     * @param queryType
     * @param dateDto
     * @return Map<本周期日期字符串 ， 上一周期日期字符串>
     */
    public static Map<String, String> getThisAndLastDateMap(String queryType, DateDto dateDto) {
        Map<String, String> map = new HashMap<>();
        List<LocalDateTime> thisList = dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        List<LocalDateTime> lastList = dateToList(queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay());
        Integer length = thisList.size() > lastList.size() ? lastList.size() : thisList.size();
        for (int i = 0; i < length; i++) {
            LocalDateTime thisDateTime = thisList.get(i);
            LocalDateTime lastDateTime = lastList.get(i);
            map.put(getDateStrByQueryType(queryType, thisDateTime), getDateStrByQueryType(queryType, lastDateTime));
        }
        return map;
    }

    /**
     * 将对应的时间类型查询转换为日期区间
     *
     * @param queryType    查询类型，日，周，月，年，自定义
     * @param startDateStr 前端传的日期开始字段
     * @param endDateStr   前端传的日期结束字段，仅类型为自定义时需要传
     * @param flag         是否查询上一周期日期
     * @return
     */
    public static DateDto dateQueryConvert(String queryType, String startDateStr, String endDateStr, Boolean flag) {
        DateDto dateDto = new DateDto();
        switch (queryType) {
            case DateType.DAY -> getStartAndEndByDay(dateDto, startDateStr, flag);
            case DateType.DAY_HALF_HOUR -> getStartAndEndByDay(dateDto, startDateStr, flag);
            case DateType.CUR_DAY -> getStartAndEndByDay(dateDto, startDateStr, flag);
            case DateType.SEVEN_DAY -> getStartAndEndBySevenDay(dateDto, endDateStr, flag);
            case DateType.WEEK -> getStartAndEndByWeek(dateDto, startDateStr, flag);
            case DateType.MONTH -> getStartAndEndByMonth(dateDto, startDateStr, flag);
            case DateType.CUR_MONTH -> getStartAndEndByMonth(dateDto, startDateStr, flag);
            case DateType.YEAR -> getStartAndEndByYear(dateDto, startDateStr, flag);
            case DateType.HIS_YEAR -> getStartAndEndByHisYear(dateDto, startDateStr, endDateStr, flag);
            case DateType.CUSTOM -> getStartAndEndByCustom(dateDto, startDateStr, endDateStr, flag);
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return dateDto;
    }

    /**
     * 将对应的时间类型查询转换为日期区间同比（上年同期）
     *
     * @param queryType    查询类型，日，周，月，年，自定义
     * @param startDateStr 前端传的日期开始字段
     * @param endDateStr   前端传的日期结束字段，仅类型为自定义时需要传
     * @param flag         是否查询上一周期日期
     * @return
     */
    public static DateDto dateQueryConvertOldYear(String queryType, String startDateStr, String endDateStr, Boolean flag) {
        DateDto dateDto = new DateDto();
        switch (queryType) {
            case DateType.DAY -> getStartAndEndByDay(dateDto, startDateStr, flag);
            case DateType.SEVEN_DAY -> getStartAndEndBySevenDay(dateDto, endDateStr, flag);
            case DateType.WEEK -> getStartAndEndByWeek(dateDto, startDateStr, flag);
            case DateType.MONTH -> getStartAndEndByMonth(dateDto, startDateStr, flag);
            case DateType.YEAR -> getStartAndEndByYear(dateDto, startDateStr, flag);
            case DateType.HIS_YEAR -> getStartAndEndByHisYear(dateDto, startDateStr, endDateStr, flag);
            case DateType.CUSTOM -> getStartAndEndByCustom(dateDto, startDateStr, endDateStr, flag);
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        String startDay = dateDto.getStartDay();
        dateDto.setStartDay(startDay.substring(0, 3) + (Integer.valueOf(startDay.substring(3, 4)) -1 ) + startDay.substring(4));
        String endDay = dateDto.getEndDay();
        dateDto.setEndDay(endDay.substring(0, 3) + (Integer.valueOf(endDay.substring(3, 4)) -1 ) + endDay.substring(4));
        return dateDto;
    }


    /**
     * 查询endDateStr，最近七天数据
     *
     * @param dateDto
     * @param endDateStr
     * @param flag
     */
    private static void getStartAndEndBySevenDay(DateDto dateDto, String endDateStr, Boolean flag) {
        //校验格式
        LocalDate localDate = checkFormat(endDateStr, YMD_PATTERN);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YMD_PATTERN);
        dateDto.setStartDay(localDate.minusDays(6).format(formatter));
        dateDto.setEndDay(endDateStr);
        if (flag) {
            getLastStartAndEndByDay(localDate, dateDto);
        }
    }

    /**
     * 将对应的时间类型查询转换为日期区间(不限制开始结束周期)
     *
     * @param queryType    查询类型，日，周，月，年，自定义
     * @param startDateStr 前端传的日期开始字段
     * @param endDateStr   前端传的日期结束字段，仅类型为自定义时需要传
     * @param flag         是否查询上一周期日期
     * @return
     */
    public static DateDto dateQueryConvertNo(String queryType, String startDateStr, String endDateStr, Boolean flag) {
        DateDto dateDto = new DateDto();
        switch (queryType) {
            case DateType.DAY -> getStartAndEndByDay(dateDto, startDateStr, flag);
            case DateType.WEEK -> getStartAndEndByWeek(dateDto, startDateStr, flag);
            case DateType.MONTH -> getStartAndEndByMonthNo(dateDto, startDateStr, endDateStr, flag);
            case DateType.YEAR -> getStartAndEndByYearNo(dateDto, startDateStr, endDateStr, flag);
            case DateType.HIS_YEAR -> getStartAndEndByHisYear(dateDto, startDateStr, endDateStr, flag);
            case DateType.CUSTOM -> getStartAndEndByCustom(dateDto, startDateStr, endDateStr, flag);
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return dateDto;
    }

    private static void getStartAndEndByHisYear(DateDto dateDto, String startDateStr, String endDateStr, Boolean flag) {
        dateDto.setStartDay(startDateStr + "-01-01");
        dateDto.setEndDay(endDateStr + "-12-31");
    }

    /**
     * 根据查询类型，返回固定格式的x轴集合
     *
     * @param queryType
     * @param list
     * @return
     */
    public static List<String> xAxisConvert(String queryType, List<LocalDateTime> list) {
        List<String> xAxisList = new ArrayList<>();
        for (LocalDateTime localDateTime : list) {
            String dateStr = localDateTime == null ? "" : getDateStrByQueryType(queryType, localDateTime);
            xAxisList.add(dateStr);
        }
        return xAxisList;
    }

    private static void yearToMonth(String startDateStr, String endDateStr, List<LocalDateTime> list) {
        yearToMonth(startDateStr, endDateStr, list, false);
    }

    private static void yearToMonth(String startDateStr, String endDateStr, List<LocalDateTime> list, boolean isAll) {
        startDateStr = startDateStr + " 00:00:00";
        LocalDateTime startDate = LocalDateTime.parse(startDateStr, FORMATE);
        list.add(startDate);

        endDateStr = endDateStr + " 00:00:00";
        LocalDateTime endDate = LocalDateTime.parse(endDateStr, FORMATE);

        LocalDateTime currentDateTime = LocalDateTime.now();
        //计算两个日期的间隔天数
        Long months = ChronoUnit.MONTHS.between(startDate, endDate);
        for (int month = 1; month <= months; month++) {
            LocalDateTime dayInMonth = startDate.plusMonths(month);
            if (!isAll && dayInMonth.isAfter(currentDateTime)) {
                continue;
            }
            list.add(dayInMonth);
        }

    }


    /**
     * dateStr前month个月份
     *
     * @param dateStr
     * @param month
     * @return
     */
    public static List<LocalDateTime> yearToMonthInt(String dateStr, int month) {
        List<LocalDateTime> list = new ArrayList<>();
        String yearMonthString = dateStr;
        YearMonth currentYearMonth = YearMonth.parse(yearMonthString, DateTimeFormatter.ofPattern("yyyy-MM"));
        List<String> previousSixMonths = new ArrayList<>();

        for (int i = 0; i < 6; i++) {

            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
            previousSixMonths.add(currentYearMonth.format(formatter));
            currentYearMonth = currentYearMonth.minusMonths(1);
        }

        // 倒序输出，从最早的月份到当前月份
        for (int i = previousSixMonths.size() - 1; i >= 0; i--) {
            LocalDateTime localDateTime = convertToLocalDateTime(previousSixMonths.get(i));
            list.add(localDateTime);
        }
        return list;
    }

    public static LocalDateTime convertToLocalDateTime(String yearMonth) {
        LocalDate localDate = LocalDate.parse(yearMonth + "-01", DateTimeFormatter.ISO_DATE);
        LocalDateTime localDateTime = localDate.atStartOfDay(); // 默认是午夜 00:00
        return localDateTime;
    }


    /**
     * 获取当前年份第一个月份
     *
     * @param year
     * @return
     */
    public static String getMonthFirst(String year) {
        return year + "-01";
    }

    /**
     * 获取当前年份第一个月份
     *
     * @param year
     * @return
     */
    public static String getYearMonthCurrent(String year) {
        String currentMonth = getCurrentMonth();
        return year + "-" + currentMonth;
    }


    public static String getCurrentMonth() {
        int currentMonth = LocalDate.now().getMonthValue();
        if (currentMonth < 10) {
            return "0" + currentMonth;
        } else {
            return String.valueOf(currentMonth);
        }
    }

    public static int getCurrentMonthInt() {
        return LocalDate.now().getMonthValue();
    }


    /**
     * 传入本月第一天的日期
     *
     * @param startDateStr
     * @param list
     */
    private static void monthToDay(String startDateStr, String endDateStr, List<LocalDateTime> list) {
        startDateStr = startDateStr + " 00:00:00";
        LocalDateTime startDate = LocalDateTime.parse(startDateStr, FORMATE);
        list.add(startDate);
        endDateStr = endDateStr + " 00:00:00";
        LocalDateTime endDate = LocalDateTime.parse(endDateStr, FORMATE);
        //计算两个日期的间隔天数
        Long days = ChronoUnit.DAYS.between(startDate, endDate);
        LocalDateTime currentDateTime = LocalDateTime.now();

        boolean isEnd = true;
        for (int day = 1; day < days; day++) {
            LocalDateTime dayInMonth = startDate.plusDays(day);

            if (dayInMonth.isAfter(currentDateTime)) {
                isEnd = false;
                continue;
            }
            list.add(dayInMonth);
        }

        if (!startDate.equals(endDate) && isEnd) {
            list.add(endDate);
        }

    }

    /**
     * 传入本周第一天的日期
     *
     * @param startDateStr
     * @param list
     */
    private static void weekToDay(String startDateStr, List<LocalDateTime> list) {
        startDateStr = startDateStr + " 00:00:00";
        LocalDateTime date = LocalDateTime.parse(startDateStr, FORMATE);
        list.add(date);
        for (int day = 1; day < 7; day++) {
            LocalDateTime dayInWeek = date.plusDays(day);
            list.add(dayInWeek);
        }
    }

    private static void dayToHour(String startDateStr, List<LocalDateTime> list) {
        dayToHour(startDateStr, list, false);
    }
    private static void dayToHalfHour(String startDateStr, List<LocalDateTime> list) {
        dayToHalfHour(startDateStr, list, false);
    }

    private static void dayToHour(String startDateStr, List<LocalDateTime> list, boolean isAll) {
        LocalDate date = LocalDate.parse(startDateStr, DATEFORMAT);

        // 如果未到达日期不构建
        LocalDateTime currentDateTime = LocalDateTime.now();
        for (int hour = 0; hour < 24; hour++) {
            LocalTime time = LocalTime.of(hour, 0, 0);
            LocalDateTime dateTime = LocalDateTime.of(date, time);
            if (!isAll && dateTime.isAfter(currentDateTime)) {
                continue;
            }
            list.add(dateTime);
        }
    }

    private static void dayToHalfHour(String startDateStr, List<LocalDateTime> list, boolean isAll) {
        LocalDate date = LocalDate.parse(startDateStr, DATEFORMAT);

        // 如果未到达日期不构建
        LocalDateTime currentDateTime = LocalDateTime.now();
        for (int hour = 0; hour < 48; hour++) {
            LocalTime time = LocalTime.of(hour/2, hour % 2 == 0 ? 0 : 30, 0);
            LocalDateTime dateTime = LocalDateTime.of(date, time);
            if (!isAll && dateTime.isAfter(currentDateTime)) {
                continue;
            }
            list.add(dateTime);
        }
    }


    private static void getStartAndEndByCustom(DateDto dateDto, String startDateStr, String endDateStr, Boolean flag) {
        LocalDate startDay = checkFormat(startDateStr, "yyyy-MM-dd");
        LocalDate endDay = checkFormat(endDateStr, "yyyy-MM-dd");
        dateDto.setStartDay(startDateStr);
        dateDto.setEndDay(endDateStr);
        if (flag) {
            // 计算间隔天数
            Period interval = Period.between(startDay, endDay);
            // 往前计算相同周期的开始时间和结束时间
            LocalDate lastStartDate = startDay.minus(interval);
            LocalDate lastEndDate = endDay.minus(interval);
            String lastStartDateStr = lastStartDate.format(DATEFORMAT);
            String lastEndDateStr = lastEndDate.format(DATEFORMAT);
            dateDto.setLastStartDay(lastStartDateStr);
            dateDto.setLastEndDay(lastEndDateStr);
        }

    }

    private static void getStartAndEndByYear(DateDto dateDto, String dateQueryStr, Boolean flag) {
        Integer year = Integer.valueOf(dateQueryStr);
        LocalDate firstDayOfYear = LocalDate.ofYearDay(year, 1)
                .with(TemporalAdjusters.firstDayOfYear());
        LocalDate lastDayOfYear = firstDayOfYear.with(TemporalAdjusters.lastDayOfYear());
        String firstDayOfYearStr = firstDayOfYear.format(DATEFORMAT);
        String lastDayOfYearStr = lastDayOfYear.format(DATEFORMAT);
        dateDto.setStartDay(firstDayOfYearStr);
        dateDto.setEndDay(lastDayOfYearStr);
        if (flag) {
            getLastStartAndEndByYear(year, dateDto, DATEFORMAT);
        }
    }

    private static void getStartAndEndByYearNo(DateDto dateDto, String startDateStr, String endDateStr, Boolean flag) {
        //将字符串按分隔符解成数组
        String[] array = startDateStr.split("-");
        Integer year = Integer.valueOf(array[0]);
        Integer month = Integer.valueOf(array[1]);
        LocalDate firstDayOfMonth = LocalDate.ofYearDay(year, 1)
                .plusMonths(month - 1)
                .with(TemporalAdjusters.firstDayOfMonth());


        String[] array1 = endDateStr.split("-");
        Integer year1 = Integer.valueOf(array1[0]);
        Integer month1 = Integer.valueOf(array1[1]);
        LocalDate firstDayOfMonth1 = LocalDate.ofYearDay(year1, 1)
                .plusMonths(month1 - 1)
                .with(TemporalAdjusters.firstDayOfMonth());


        LocalDate lastDayOfMonth = firstDayOfMonth1.with(TemporalAdjusters.lastDayOfMonth());
        String firstDayOfMonthStr = firstDayOfMonth.format(DATEFORMAT);
        String lastDayOfMonthStr = lastDayOfMonth.format(DATEFORMAT);
        dateDto.setStartDay(firstDayOfMonthStr);
        dateDto.setEndDay(lastDayOfMonthStr);
        if (flag) {
            getLastStartAndEndByMonth(year, month, dateDto, DATEFORMAT);
        }
//        Integer year = Integer.valueOf(dateQueryStr);
//        LocalDate firstDayOfYear = LocalDate.ofYearDay(year, 1)
//                .with(TemporalAdjusters.firstDayOfYear());
////        LocalDate lastDayOfYear = firstDayOfYear.with(TemporalAdjusters.lastDayOfYear());
//
//        Integer year1 = Integer.valueOf(endQueryStr);
//        LocalDate firstDayOfYear1 = LocalDate.ofYearDay(year1, 1)
//                .with(TemporalAdjusters.firstDayOfYear());
//        LocalDate lastDayOfYear1 = firstDayOfYear1.with(TemporalAdjusters.lastDayOfYear());
//
//        String firstDayOfYearStr = firstDayOfYear.format(DATEFORMAT);
//        String lastDayOfYearStr = lastDayOfYear1.format(DATEFORMAT);
//        dateDto.setStartDay(firstDayOfYearStr);
//        dateDto.setEndDay(lastDayOfYearStr);
//        if (flag) {
//            getLastStartAndEndByYear(year, dateDto, DATEFORMAT);
//        }
    }

    private static void getLastStartAndEndByYear(Integer year, DateDto dateDto, DateTimeFormatter formate) {
        LocalDate firstDayOfYear = LocalDate.ofYearDay(year - 1, 1)
                .with(TemporalAdjusters.firstDayOfYear());
        LocalDate lastDayOfYear = firstDayOfYear.with(TemporalAdjusters.lastDayOfYear());
        String firstDayOfYearStr = firstDayOfYear.format(DATEFORMAT);
        String lastDayOfYearStr = lastDayOfYear.format(DATEFORMAT);
        dateDto.setLastStartDay(firstDayOfYearStr);
        dateDto.setLastEndDay(lastDayOfYearStr);
    }

    private static void getStartAndEndByMonth(DateDto dateDto, String dateQueryStr, Boolean flag) {
        //将字符串按分隔符解成数组
        String[] array = dateQueryStr.split("-");
        Integer year = Integer.valueOf(array[0]);
        Integer month = Integer.valueOf(array[1]);
        LocalDate firstDayOfMonth = LocalDate.ofYearDay(year, 1)
                .plusMonths(month - 1)
                .with(TemporalAdjusters.firstDayOfMonth());
        Boolean isAddOneDay = ThreadLocalUtil.get("is_sub_one_day");
        if (isAddOneDay != null && isAddOneDay) {
            firstDayOfMonth.plusDays(-1);
        }
        LocalDate lastDayOfMonth = firstDayOfMonth.with(TemporalAdjusters.lastDayOfMonth());
        String firstDayOfMonthStr = firstDayOfMonth.format(DATEFORMAT);
        String lastDayOfMonthStr = lastDayOfMonth.format(DATEFORMAT);
        dateDto.setStartDay(firstDayOfMonthStr);
        dateDto.setEndDay(lastDayOfMonthStr);
        if (flag) {
            getLastStartAndEndByMonth(year, month, dateDto, DATEFORMAT);
        }
    }

    private static void getStartAndEndByMonthNo(DateDto dateDto, String startDateStr, String endDateStr, Boolean flag) {


        //将字符串按分隔符解成数组
        String[] array = startDateStr.split("-");
        Integer year = Integer.valueOf(array[0]);
        Integer month = Integer.valueOf(array[1]);
        Integer day = Integer.valueOf(array[2]);
        LocalDate firstDayOfMonth = LocalDate.of(year, month, day);


        String[] array1 = endDateStr.split("-");
        Integer year1 = Integer.valueOf(array1[0]);
        Integer month1 = Integer.valueOf(array1[1]);
        Integer day1 = Integer.valueOf(array1[2]);
        LocalDate lastDayOfMonth = LocalDate.of(year1, month1, day1);


        String firstDayOfMonthStr = firstDayOfMonth.format(DATEFORMAT);
        String lastDayOfMonthStr = lastDayOfMonth.format(DATEFORMAT);
        dateDto.setStartDay(firstDayOfMonthStr);
        dateDto.setEndDay(lastDayOfMonthStr);
        if (flag) {
            getLastStartAndEndByMonth(year, month, dateDto, DATEFORMAT);
        }
    }

    private static void getLastStartAndEndByMonth(Integer year, Integer month, DateDto dateDto, DateTimeFormatter formate) {
        LocalDate firstDayOfMonth = LocalDate.ofYearDay(year, 1)
                .plusMonths(month - 2)
                .with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDayOfMonth = firstDayOfMonth.with(TemporalAdjusters.lastDayOfMonth());
        String firstDayOfMonthStr = firstDayOfMonth.format(formate);
        String lastDayOfMonthStr = lastDayOfMonth.format(formate);
        dateDto.setLastStartDay(firstDayOfMonthStr);
        dateDto.setLastEndDay(lastDayOfMonthStr);
    }

    private static void getStartAndEndByWeek(DateDto dateDto, String dateQueryStr, Boolean flag) {
        //将字符串按分隔符解成数组
        String[] array = dateQueryStr.split("-");
        Integer year = Integer.valueOf(array[0]);
        Integer week = Integer.valueOf(array[1]);
        LocalDate firstDayOfWeek = LocalDate.ofYearDay(year, 1)
                .plusWeeks(week - 1)
                .with(DayOfWeek.MONDAY);
        LocalDate lastDayOfWeek = firstDayOfWeek.plusDays(6);
        String firstDayOfWeekStr = firstDayOfWeek.format(DATEFORMAT);
        String lastDayOfWeekStr = lastDayOfWeek.format(DATEFORMAT);
        dateDto.setStartDay(firstDayOfWeekStr);
        dateDto.setEndDay(lastDayOfWeekStr);
        if (flag) {
            getLastStartAndEndByWeek(firstDayOfWeek, dateDto, DATEFORMAT);
        }
    }

    private static void getLastStartAndEndByWeek(LocalDate firstDayOfWeek, DateDto dateDto, DateTimeFormatter formate) {
        LocalDate startDate = firstDayOfWeek.plusDays(-7);
        LocalDate lastDayOfWeek = startDate.plusDays(6);
        String firstDayOfWeekStr = startDate.format(formate);
        String lastDayOfWeekStr = lastDayOfWeek.format(formate);
        dateDto.setLastStartDay(firstDayOfWeekStr);
        dateDto.setLastEndDay(lastDayOfWeekStr);
    }

    private static void getStartAndEndByDay(DateDto dateDto, String dateQueryStr, Boolean flag) {
        //校验格式
        LocalDate localDate = checkFormat(dateQueryStr, "yyyy-MM-dd");
        dateDto.setStartDay(dateQueryStr);
        dateDto.setEndDay(dateQueryStr);
        if (flag) {
            getLastStartAndEndByDay(localDate, dateDto);
        }
    }

    private static void getLastStartAndEndByDay(LocalDate startDate, DateDto dateDto) {
        LocalDate lastDate = startDate.minusDays(1);
        String dateStr = lastDate.format(DATEFORMAT);
        dateDto.setLastStartDay(dateStr);
        dateDto.setLastEndDay(dateStr);
    }

    public static LocalDate checkFormat(String startDateStr, String pattern) {
        try {
            return LocalDate.parse(startDateStr, DateTimeFormatter.ofPattern(pattern));
        } catch (Exception e) {
            e.printStackTrace();
            throw new ConditionException("日期格式有误，请传入{" + pattern + "}格式");
        }
    }

    public static LocalDateTime toDateTime(String dateStr, String pattern) {
        DateTime parse = DateUtil.parse(dateStr, pattern);
        return LocalDateTime.parse(parse.toString(), DateTimeFormatter.ofPattern(PATTERN));
    }

    public static LocalDate toDate(String dateStr, String pattern) {
        DateTime parse = DateUtil.parse(dateStr, pattern);
        return LocalDateTime.parse(parse.toString(), DateTimeFormatter.ofPattern(PATTERN)).toLocalDate();
    }

    /**
     * 获取日期开始时间
     *
     * @param date
     * @return
     */
    public static LocalDateTime getStartTime(LocalDate date) {
        return date.atTime(0, 0, 0);
    }

    /**
     * 获取日期开始时间
     *
     * @param date
     * @return
     */
    public static LocalDateTime getEndTime(LocalDate date) {
        return date.atTime(23, 59, 59);
    }

    /**
     * 获取时间的月开始时间
     *
     * @param dateTime
     * @param monthAgoNum
     */
    public static LocalDateTime getMonthStartDate(LocalDateTime dateTime, int monthAgoNum) {
        LocalDateTime dateTime1 = LocalDateTime.of(dateTime.getYear(), dateTime.getMonth().getValue(), 1, 0, 0, 0);
        return dateTime1.minus(monthAgoNum, ChronoUnit.MONTHS);
    }
    /**
     * 获取时间的月开始时间
     *
     * @param dateTime
     */
    public static LocalDate getMonthStartDate(LocalDate dateTime) {
        return LocalDate.of(dateTime.getYear(), dateTime.getMonth().getValue(), 1);
    }

    /**
     * 获取时间的月结束时间
     *
     * @param dateTime
     * @param monthAgoNum
     */
    public static LocalDateTime getMonthEndDate(LocalDateTime dateTime, int monthAgoNum) {
        LocalDateTime monthStartDate = getMonthStartDate(dateTime, monthAgoNum - 1);
        LocalDateTime localDateTime = monthStartDate.plus(-1, ChronoUnit.DAYS);
        LocalDateTime res = LocalDateTime.of(localDateTime.getYear(), localDateTime.getMonth().getValue(), localDateTime.getDayOfMonth(), 23, 59, 59);
        return res;
    }

    /**
     * 获取时间的月结束时间
     *
     * @param dateTime
     */
    public static LocalDate getMonthEndDate(LocalDate dateTime) {
        LocalDateTime monthStartDate = getMonthStartDate(dateTime.atStartOfDay(), - 1);
        LocalDateTime localDateTime = monthStartDate.plus(-1, ChronoUnit.DAYS);
        LocalDate res = LocalDate.of(localDateTime.getYear(), localDateTime.getMonth().getValue(), localDateTime.getDayOfMonth());
        return res;
    }

    /**
     * 最近天数，不包括当天
     *
     * @param interval
     * @return
     */
    public static List<LocalDate> getLastDateList(int interval) {
        LocalDate date = LocalDate.now().plusDays(-interval);
        List<LocalDate> res = new ArrayList<>();
        res.add(date);
        for (int i = 1; i < interval; i++) {
            res.add(date.plusDays(i));
        }
        return res;
    }


    /**
     * 日期转字符串
     *
     * @param dateList
     * @param format
     */
    public static List<String> dateToString(List<LocalDate> dateList, String format) {
        List<String> res = new ArrayList<>();
        dateList.forEach(m -> res.add(m.format(DateTimeFormatter.ofPattern(format))));
        return res;
    }

    public static String dateTimeToString(LocalDateTime measureTime, String format) {
        return measureTime.format(DateTimeFormatter.ofPattern(format));
    }

    public static String dateToString(LocalDate measureTime, String format) {
        return measureTime.format(DateTimeFormatter.ofPattern(format));
    }
    public static String dateToString(LocalDateTime measureTime, String format) {
        return measureTime.format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 获取月份，从参数开始的时间到当前时间的月初日期
     *
     * @param monthStartDate
     * @return
     */
    public static List<LocalDate> getMonths(LocalDate monthStartDate) {
        List<LocalDate> res = new ArrayList<>();

        while (true) {
            if (monthStartDate.compareTo(LocalDate.now()) > 0) {
                return res;
            }
            res.add(monthStartDate);
            monthStartDate = monthStartDate.plus(1, ChronoUnit.MONTHS);
        }

    }

    /**
     * 获取两时间内的天时间集
     *
     * @param startDate
     * @param enDate
     * @return
     */
    public static List<LocalDate> getDateDayList(LocalDate startDate, LocalDate enDate) {
        List<LocalDate> dateList = new ArrayList<>();
        while (startDate.compareTo(enDate) < 1) {
            dateList.add(startDate);
            startDate = startDate.plusDays(1);
        }
        return dateList;
    }

    /**
     * 获取两时间内的天时间集
     *
     * @param startDate
     * @param enDate
     * @return
     */
    public static List<String> getDateDayList(LocalDate startDate, LocalDate enDate, String format) {
        List<String> res = new ArrayList<>();
        while (startDate.compareTo(enDate) < 1) {
            res.add(startDate.format(DateTimeFormatter.ofPattern(format)));
            startDate = startDate.plusDays(1);
        }
        return res;
    }

    /**
     * 获取当前时间的最近时间，间隔2小时
     *
     * @param day
     * @return
     */
    public static List<String> getLastDayHour(LocalDateTime day) {
        List<String> res = new ArrayList<>();
        int hour = day.getHour();
        if (hour % 2 == 1) {
            day = day.plus(-1, ChronoUnit.HOURS);
        }
        res.add(day.format(DateTimeFormatter.ofPattern(YMD_H_PATTERN)));
        for (int i = 0; i < 12; i++) {
            day = day.plus(-2, ChronoUnit.HOURS);
            res.add(day.format(DateTimeFormatter.ofPattern(YMD_H_PATTERN)));
        }
        return res;
    }

    /**
     * 获取最近日期集，不包括day
     *
     * @param day
     * @param dayNum
     * @return
     */
    public static List<String> getLastDay(LocalDateTime day, int dayNum) {
        List<String> res = new ArrayList<>();
        for (int i = 0; i < dayNum; i++) {
            day = day.plus(-1, ChronoUnit.DAYS);
            res.add(day.format(DateTimeFormatter.ofPattern(MD_PATTERN)));
        }
        return res;
    }

    /**
     * @param day
     * @param monthNum
     * @return
     */
    public static List<String> getLastMonth(LocalDateTime day, int monthNum) {
        List<String> res = new ArrayList<>();
        for (int i = 0; i < monthNum; i++) {
            res.add(day.format(DateTimeFormatter.ofPattern(YM_PATTERN)));
            day = day.plus(-1, ChronoUnit.MONTHS);
        }
        return res;
    }

    public static List<String> getLastMonth(LocalDateTime day, int monthNum, String format) {
        List<String> res = new ArrayList<>();
        for (int i = 0; i < monthNum; i++) {
            res.add(day.format(DateTimeFormatter.ofPattern(format)));
            day = day.plus(-1, ChronoUnit.MONTHS);
        }
        return res;
    }

    /**
     * 获取时间的月结束时间(天为当天)
     *
     * @param dateTime
     * @param monthAgoNum
     */
    public static LocalDateTime getMonthEndCurDate(LocalDateTime dateTime, int monthAgoNum) {
        LocalDateTime tmp = getMonthEndDate(dateTime, monthAgoNum);
        int dayOfMonth = LocalDate.now().getDayOfMonth();
        int lastDayOfMonth = tmp.getDayOfMonth();
        return tmp.withDayOfMonth(dayOfMonth < lastDayOfMonth ? dayOfMonth : lastDayOfMonth);
    }

    public static Boolean isCurrentYear(String date) {
        try {
            int year = Integer.parseInt(date.substring(0, 4));
            return year == Year.now().getValue();
        } catch (NumberFormatException e) {
            return false;
        }
    }


    public static String formatDate(Date date, String format) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
        return dateFormat.format(date);
    }

    /**
     * 添加一环比周期
     * @param queryType
     * @param dateStr
     * @return
     */
    public static String addOneLinkRelative(String queryType, String dateStr) {
        String result = "";

        switch (queryType) {
            case DateType.WEEK -> {
                LocalDate date = toDate(dateStr, YMD_PATTERN);
                LocalDate date1 = date.plusDays(7);
                result = dateToString(date1, YMD_PATTERN);
            }
            case DateType.MONTH -> {
                LocalDate date = toDate(dateStr, YMD_PATTERN);
                LocalDate date1 = date.plusMonths(1);
                result = dateToString(date1, YMD_PATTERN);
            }
            case DateType.YEAR -> {
                LocalDate date = toDate(dateStr, YM_PATTERN);
                LocalDate date1 = date.plusYears(1);
                result = dateToString(date1, YM_PATTERN);
            }
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return result;
    }
    /**
     * 添加一环比周期
     * @param queryType
     * @param dateStr
     * @return
     */
    public static String addSubtractLinkRelative(String queryType, String dateStr) {
        String result = "";

        switch (queryType) {
            case DateType.WEEK -> {
                LocalDate date = toDate(dateStr, YEAR_WEEK_PATTERN);
                LocalDate date1 = date.plusDays(-7);
                result = dateToString(date1, YEAR_WEEK_PATTERN);
            }
            case DateType.MONTH -> {
                LocalDate date = toDate(dateStr, YM_PATTERN);
                LocalDate date1 = date.plusMonths(-1);
                result = dateToString(date1, YM_PATTERN);
            }
            case DateType.YEAR -> {
                LocalDate date = toDate(dateStr, YEAR_PATTERN);
                LocalDate date1 = date.plusYears(-1);
                result = dateToString(date1, YEAR_PATTERN);
            }
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return result;
    }

    public static String addSubtractLinkRelative(String queryType, String dateStr, String pattern) {
        String result = "";

        switch (queryType) {
            case DateType.WEEK -> {
                LocalDate date = toDate(dateStr, pattern);
                LocalDate date1 = date.plusDays(-7);
                result = dateToString(date1, pattern);
            }
            case DateType.MONTH -> {
                LocalDate date = toDate(dateStr, pattern);
                LocalDate date1 = date.plusMonths(-1);
                result = dateToString(date1, pattern);
            }
            case DateType.YEAR -> {
                LocalDate date = toDate(dateStr, pattern);
                LocalDate date1 = date.plusYears(-1);
                result = dateToString(date1, pattern);
            }
            default -> throw new ConditionException("查询类型有误，请修改后再试");
        }
        return result;
    }

    /**
     * 获取上一周的对应天
     * @param dateStr
     * @return
     */
    public static String getLastWeekday(String dateStr) {
        // 定义日期格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 将字符串解析为LocalDate对象
        LocalDate currentDate = LocalDate.parse(dateStr, formatter);
        // 获取上一周的同一天
        String result = String.valueOf(currentDate.minusWeeks(1));
        return result;
    }

    public static void main(String[] args) {
        System.out.println(addOneLinkRelative("week", "2024-09-20"));
        System.out.println(addOneLinkRelative("week", "2024-09-19"));
        System.out.println(addOneLinkRelative("month", "2024-09-18"));
        System.out.println(addOneLinkRelative("month", "2024-09-01"));
        System.out.println(addOneLinkRelative("year", "2024-09"));
        System.out.println(addOneLinkRelative("year", "2022-09"));
    }
}
